// 198. 打家劫舍
// 你是一个专业的小偷，计划偷窃沿街的房屋。每间房内都藏有一定的现金，
// 影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统，
// 如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警。

// 给定一个代表每个房屋存放金额的非负整数数组，计算你 不触动警报装置的情况下 ，
// 一夜之内能够偷窃到的最高金额。
// 示例 1：

// 输入：[1,2,3,1]
// 输出：4
// 解释：偷窃 1 号房屋 (金额 = 1) ，然后偷窃 3 号房屋 (金额 = 3)。
//      偷窃到的最高金额 = 1 + 3 = 4 。
// 思路：递推公式：不能连续偷两间房子 但是还是要考虑dp[i-1]，但不是偷i-1
//  dp[i]=Math.max(dp[i-2],muns[i],dp[i-1])
// dp初始化：dp=nums[0],Math.max(nums[0],nums[1])
/**
 * @param {number[]} nums
 * @return {number}
 */
 var rob = function(nums) {
    const dp=[nums[0],Math.max(nums[0],nums[1])];
    for(let i=2;i<nums.length;i++){
        dp[i]=Math.max(nums[i]+dp[i-2],dp[i-1]);
    }
    return dp[nums.length-1];
 }

//  213. 打家劫舍 II
//  你是一个专业的小偷，计划偷窃沿街的房屋，每间房内都藏有一定的现金。
// 这个地方所有的房屋都 围成一圈 ，这意味着第一个房屋和最后一个房屋是紧挨着的。
// 同时，相邻的房屋装有相互连通的防盗系统，如果两间相邻的房屋在同一晚上被小偷闯入，
// 系统会自动报警 。
 
//  给定一个代表每个房屋存放金额的非负整数数组，计算你 在不触动警报装置的情况下 ，
// 今晚能够偷窃到的最高金额。
 
//  示例 1：
 
//  输入：nums = [2,3,2]
//  输出：3
//  解释：你不能先偷窃 1 号房屋（金额 = 2），然后偷窃 3 号房屋（金额 = 2）,
//  因为他们是相邻的。  
// 思路：考虑两种情况，成环 1. 含头不含尾 2. 含尾不含头 考虑两种 比较大小
var rob=function(nums){
    var robMoney=function(nums,start,end){
        if(start==end) return nums[start];// 注意要判断如果相等就直接返回start
        let dp=new Array(nums.length);
        dp[start]=nums[start];
        dp[start+1]=Math.max(nums[start],nums[start+1]);
        for(let i=start+2;i<=end;i++){
            dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i])
        }
        return dp[end]
    }
    const n=nums.length;
    if(n==0) return 0;
    if(n==1) return nums[0];
    const result1=robMoney(nums,0,n-2);
    const result2=robMoney(nums,1,n-1);
    return Math.max(result1,result2);
}

// 337. 打家劫舍 III
// 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口，我们称之为 root 。

// 除了 root 之外，每栋房子有且只有一个“父“房子与之相连。一番侦察之后，
// 聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 
// 如果 两个直接相连的房子在同一天晚上被打劫 ，房屋将自动报警。
// 示例一：
// 给定二叉树的 root 。返回 在不触动警报的情况下 ，小偷能够盗取的最高金额 。
// 输入: root = [3,2,3,null,3,null,1]
// 输出: 7 
// 解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

// 思路：后序遍历二叉树 选择最大的
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
 const rob = root => {
    // 后序遍历函数
    const postOrder = node => {
        // 递归出口
        if (!node) return [0, 0];
        // 遍历左子树
        const left = postOrder(node.left);
        // 遍历右子树
        const right = postOrder(node.right);
        // 不偷当前节点，左右子节点都可以偷或不偷，取最大值
        const DoNot = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        // 偷当前节点，左右子节点只能不偷
        const Do = node.val + left[0] + right[0];
        // [不偷，偷]
        return [DoNot, Do];
    };
    const res = postOrder(root);
    // 返回最大值
    return Math.max(...res);
};